import { EventEmitter } from 'events';
import { RemoteConfig, RemoteProtocolType } from './remote';
import { Endpoint, EndpointStatus } from './endpoint';
import { WebSocketServer } from './websocket/server';
import { ActorSystem } from '../actor/actorSystem';

export class EndpointManager extends EventEmitter {
  private endpoints: Map<string, Endpoint> = new Map();
  private server?: WebSocketServer;
  private config?: RemoteConfig;
  private reconnectTimers: Map<string, NodeJS.Timeout> = new Map();
  private readonly maxReconnectAttempts = 5;
  private readonly initialReconnectDelay = 1000; // 1秒
  private readonly maxReconnectDelay = 30000; // 30秒
  private system: ActorSystem;

  constructor(system: ActorSystem) {
    super();
    this.system = system;
    console.log(`[ENDPOINT_MANAGER] Initializing...`);
  }

  setConfig(config: RemoteConfig): void {
    console.log(`[ENDPOINT_MANAGER] Setting config:`, {
      hostname: config.hostname,
      port: config.port,
      protocolType: config.protocolType,
      hasSerializer: !!config.serializer
    });
    this.config = config;
  }

  async start(): Promise<void> {
    try {
      console.log(`[ENDPOINT_MANAGER] Starting server on ${this.config?.hostname}:${this.config?.port} using ${this.config?.protocolType} protocol`);
      
      if (!this.config) {
        throw new Error('EndpointManager not configured');
      }
      
      // 根据协议类型选择不同的服务器实现
      if (this.config.protocolType === RemoteProtocolType.WebSocket) {
        // 创建WebSocket服务器
        this.server = new WebSocketServer(this.config);
        
        // 监听消息事件
        this.server.on('message', async (message: any, clientId: string) => {
          console.log(`[ENDPOINT_MANAGER] Received WebSocket message from ${clientId}`);
          try {
            await this.handleMessage(clientId, message);
          } catch (error) {
            console.error(`[ENDPOINT_MANAGER] Error handling WebSocket message from ${clientId}:`, error);
          }
        });
        
        // 启动WebSocket服务器
        await this.server.start(this.config.hostname, this.config.port);
        console.log(`[ENDPOINT_MANAGER] WebSocket server started on ${this.config.hostname}:${this.config.port}`);
      } 
      else if (this.config.protocolType === RemoteProtocolType.Libp2p) {
        // 使用libp2p提供者
        if (!this.config.libp2pProvider) {
          throw new Error('Libp2p provider not configured');
        }
        
        // 设置libp2p消息处理
        this.config.libp2pProvider.on('message', async (peerId: string, message: any) => {
          console.log(`[ENDPOINT_MANAGER] Received libp2p message from ${peerId}`);
          try {
            await this.handleMessage(peerId, message);
          } catch (error) {
            console.error(`[ENDPOINT_MANAGER] Error handling libp2p message from ${peerId}:`, error);
          }
        });
        
        console.log(`[ENDPOINT_MANAGER] Using existing libp2p provider for communication`);
      }
      else {
        throw new Error(`Unsupported protocol type: ${this.config.protocolType}`);
      }
      
    } catch (error) {
      console.error(`[ENDPOINT_MANAGER] Failed to start server:`, error);
      throw error;
    }
  }

  async sendMessage(address: string, message: unknown): Promise<void> {
    console.log(`[ENDPOINT_MANAGER] Preparing to send message to ${address}`);
    console.log(`[ENDPOINT_MANAGER] Message details:`, {
      type: typeof message,
      isRemoteMessage: message && typeof message === 'object' && 'type' in message,
      targetPID: (message as any)?.targetPID?.toString?.(),
      messageType: (message as any)?.type
    });
    
    if (!this.config) {
      throw new Error('EndpointManager not configured');
    }
    
    // 根据协议类型选择不同的发送方式
    if (this.config.protocolType === RemoteProtocolType.Libp2p) {
      if (!this.config.libp2pProvider) {
        throw new Error('Libp2p provider not configured');
      }
      
      try {
        // 使用libp2p发送消息
        console.log(`[ENDPOINT_MANAGER] Sending message via libp2p to ${address}`);
        await this.config.libp2pProvider.sendMessage(address, message);
        console.log(`[ENDPOINT_MANAGER] Message sent successfully via libp2p to ${address}`);
      } catch (error) {
        console.error(`[ENDPOINT_MANAGER] Failed to send message via libp2p to ${address}:`, error);
        throw error;
      }
    } 
    else {
      // 使用WebSocket发送消息
      const endpoint = this.getOrCreateEndpoint(address);
      
      try {
        // 如果端点未连接，尝试连接
        if (endpoint.status !== EndpointStatus.Connected) {
          console.log(`[ENDPOINT_MANAGER] Endpoint not connected, connecting to ${address}...`);
          await endpoint.connect();
          console.log(`[ENDPOINT_MANAGER] Connection established to ${address}`);
        }
        
        await endpoint.send(message);
        console.log(`[ENDPOINT_MANAGER] Message sent successfully via WebSocket to ${address}`);
        
      } catch (error) {
        console.error(`[ENDPOINT_MANAGER] Failed to send message via WebSocket to ${address}:`, error);
        if (endpoint) {
          console.log(`[ENDPOINT_MANAGER] Endpoint status:`, endpoint.status);
        }
        throw error;
      }
    }
  }

  async shutdown(): Promise<void> {
    console.log(`[ENDPOINT_MANAGER] Shutting down...`);
    
    // 关闭所有端点
    const endpointClosingPromises = Array.from(this.endpoints.values()).map(endpoint => {
      try {
        return endpoint.disconnect();
      } catch (error) {
        console.error(`[ENDPOINT_MANAGER] Error closing endpoint:`, error);
        return Promise.resolve();
      }
    });
    
    // 等待所有端点关闭
    await Promise.all(endpointClosingPromises);
    console.log(`[ENDPOINT_MANAGER] All endpoints closed`);
    
    // 清空端点集合
    this.endpoints.clear();
    console.log(`[ENDPOINT_MANAGER] Endpoints collection cleared`);
    
    // 关闭服务器
    if (this.server) {
      try {
        this.server.close();
        console.log(`[ENDPOINT_MANAGER] Server closed`);
      } catch (error) {
        console.error(`[ENDPOINT_MANAGER] Error closing server:`, error);
      }
      this.server = undefined;
    }
    
    // 清除所有重连定时器
    for (const [address, timer] of this.reconnectTimers.entries()) {
      clearTimeout(timer);
      console.log(`[ENDPOINT_MANAGER] Cleared reconnect timer for ${address}`);
    }
    
    this.reconnectTimers.clear();
    console.log(`[ENDPOINT_MANAGER] Shutdown complete`);
  }

  private getOrCreateEndpoint(address: string): Endpoint {
    let endpoint = this.endpoints.get(address);
    
    if (!endpoint) {
      console.log(`[ENDPOINT_MANAGER] Creating new endpoint for ${address}`);
      
      if (!this.config) {
        throw new Error('Configuration not set');
      }
      
      endpoint = new Endpoint(address, this.config);
      
      // 设置事件处理
      endpoint.on('connected', () => {
        console.log(`[ENDPOINT_MANAGER] Endpoint ${address} connected`);
        this.clearReconnectTimer(address);
      });
      
      endpoint.on('disconnected', () => {
        console.log(`[ENDPOINT_MANAGER] Endpoint ${address} disconnected`);
        this.scheduleReconnect(address);
      });
      
      endpoint.on('error', (error: Error) => {
        console.error(`[ENDPOINT_MANAGER] Endpoint ${address} error:`, error);
        this.scheduleReconnect(address);
      });
      
      endpoint.on('message', async (message: any) => {
        try {
          await this.handleMessage(address, message);
        } catch (error) {
          console.error(`[ENDPOINT_MANAGER] Error handling message from ${address}:`, error);
        }
      });
      
      this.endpoints.set(address, endpoint);
    }
    
    return endpoint;
  }

  private clearReconnectTimer(address: string): void {
    const timer = this.reconnectTimers.get(address);
    if (timer) {
      clearTimeout(timer);
      this.reconnectTimers.delete(address);
    }
  }

  private scheduleReconnect(address: string, attempt: number = 0): void {
    this.clearReconnectTimer(address);
    
    if (attempt >= this.maxReconnectAttempts) {
      console.log(`[ENDPOINT_MANAGER] Max reconnection attempts (${this.maxReconnectAttempts}) reached for ${address}`);
      return;
    }
    
    // 计算指数退避延迟
    const delay = Math.min(
      this.initialReconnectDelay * Math.pow(2, attempt),
      this.maxReconnectDelay
    );
    
    console.log(`[ENDPOINT_MANAGER] Scheduling reconnect for ${address} in ${delay}ms (attempt ${attempt + 1}/${this.maxReconnectAttempts})`);
    
    const timer = setTimeout(async () => {
      try {
        const endpoint = this.endpoints.get(address);
        if (endpoint && endpoint.status !== EndpointStatus.Connected) {
          console.log(`[ENDPOINT_MANAGER] Attempting to reconnect to ${address}`);
          await endpoint.connect();
        }
      } catch (error) {
        console.error(`[ENDPOINT_MANAGER] Reconnection attempt failed for ${address}:`, error);
        this.scheduleReconnect(address, attempt + 1);
      }
    }, delay);
    
    this.reconnectTimers.set(address, timer);
  }

  private async handleMessage(address: string, message: any): Promise<void> {
    console.log(`[ENDPOINT_MANAGER] Processing message from ${address}`);
    
    try {
      // 解析消息
      let parsedMessage;
      if (typeof message === 'string') {
        try {
          parsedMessage = JSON.parse(message);
        } catch (error) {
          console.error(`[ENDPOINT_MANAGER] Failed to parse message:`, error);
          return;
        }
      } else {
        parsedMessage = message;
      }
      
      // 发出消息事件
      this.emit('message', address, parsedMessage);
      
    } catch (error) {
      console.error(`[ENDPOINT_MANAGER] Error processing message:`, error);
    }
  }
} 